package com.denlaku.longan.controller.impl;

import com.denlaku.longan.anno.VarBy;
import com.denlaku.longan.controller.ResourceController;
import com.denlaku.longan.http.Resp;
import com.denlaku.longan.http.Return;
import com.denlaku.longan.qo.Query;
import com.denlaku.longan.service.ResourceService;
import com.denlaku.longan.util.DateUtil;
import com.denlaku.longan.util.SnowflakeUtils;
import com.denlaku.longan.vo.PageBy;
import com.denlaku.longan.vo.Resource;
import com.github.pagehelper.PageHelper;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * @author tianx
 */
@RestController
@Slf4j
public class ResourceControllerImpl implements ResourceController {
	private static final long MAX_FILE_SIZE = 64 * 1204 * 1204;

	@Autowired
	private ResourceService resourceService;

	@Override
	public Return<Resource> upload(MultipartHttpServletRequest request) {
		Iterator<String> fileNames = request.getFileNames();
		if (!fileNames.hasNext()) {
			return Resp.error("没有选择文件！");
		}
		String contentLength = request.getHeader("content-length");
		if (Long.parseLong(contentLength) > MAX_FILE_SIZE) {
			return Resp.error("file size (" + contentLength + ") exceeds the maximum (" + MAX_FILE_SIZE + ")");
		}
		String fileName = fileNames.next();
		MultipartFile mFile = request.getFile(fileName);
		if (mFile == null) {
			return Resp.error("file is not exists");
		}
		Resource resource = newResource(mFile);
		File file = resourceService.toFile(resource);
		File parent = file.getParentFile();
		try {
			if (parent.exists() || parent.mkdirs()) {
				mFile.transferTo(file);
				resourceService.add(resource);
			}
		} catch (IllegalStateException | IOException e) {
			log.error("upload resource error", e);
			return Resp.error("上传文件失败");
		}
		return Resp.success(resource);
	}

	private Resource newResource(MultipartFile mFile) {
		Resource resource = new Resource();
		resource.setId(SnowflakeUtils.nextId());
		resource.setName(mFile.getOriginalFilename());
		resource.setContentType(mFile.getContentType());
		resource.setSize(mFile.getSize());
		resource.setPath(DateUtil.format(new Date(), "yyyy-MM-dd"));
		return resource;
	}

	@Override
	public void download(@PathVariable("id") Long id, HttpServletResponse response) {
		Resource resource = resourceService.get(Query.of(id));
		if (resource == null) {
			return;
		}
		File file = resourceService.toFile(resource);
		if (!file.exists()) {
			response.setStatus(404);
			return;
		}
		try {
			String name = resource.getName();
			response.setContentType(resource.getContentType());
			response.setContentLengthLong(file.length());
			response.addHeader(HttpHeaders.CONTENT_DISPOSITION,
					"attachment; filename=" + URLEncoder.encode(name, StandardCharsets.UTF_8.name()));
			Files.copy(file.toPath(), response.getOutputStream());
		} catch (IOException e) {
			log.error("download error", e);
		}
	}

	@SneakyThrows
	@Override
	public Return<Void> delete(Long id) {
		Resource resource = resourceService.get(Query.of(id));
		if (resource == null) {
			return Resp.success();
		}
		File file = resourceService.toFile(resource);
		if (!file.exists() || file.delete()) {
			resourceService.delete(Query.of(id));
		}
		return Resp.success();
	}

	@VarBy
	@Override
	public Return<List<Resource>> pageList(@RequestBody Resource resource, PageBy pageBy) {
		PageHelper.startPage(pageBy.getPage(), pageBy.getSize());
		List<Resource> list = resourceService.list(resource);
		return Resp.success(list);
	}
}
